/* CoralCube | Massively Multiplayer Online Role-Playing Game(MMORPG) Emulator.
|* 
|* Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
|*               2008-2010 CoralCube <http://www.CoralCube.com/>
|*
|* This program is free software. You can redistribute it and/or modify it under the terms of 
|* the GNU General Public License as published by the Free Software Foundation, either 
|* version 2 of the License.
|*
|* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, 
|* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
|* See the GNU General Public License for more details.
|*
|* You should have received a copy of the GNU General Public License along with this program. 
|* If not, see <http://www.gnu.org/licenses/>.
|*/

/* ScriptData
Name: npc_commandscript
%Complete: 100
Comment: All npc related commands
Category: commandscripts
EndScriptData */

#include "ScriptMgr.h"
#include "ObjectMgr.h"
#include "Chat.h"
#include "Transport.h"
#include "CreatureGroups.h"
#include "TargetedMovementGenerator.h"                      // for HandleNpcUnFollowCommand

class npc_commandscript : public CommandScript
{
public:
    npc_commandscript() : CommandScript("npc_commandscript") { }

    ChatCommand* GetCommands() const
    {
        static ChatCommand npcAddCommandTable[] =
        {
            { "formation",      SEC_MODERATOR,      false, &HandleNpcAddFormationCommand,      "", NULL },
            { "item",           SEC_GAMEMASTER,     false, &HandleNpcAddVendorItemCommand,     "", NULL },
            { "move",           SEC_GAMEMASTER,     false, &HandleNpcAddMoveCommand,           "", NULL },
            { "temp",           SEC_GAMEMASTER,     false, &HandleNpcAddTempSpawnCommand,      "", NULL },
            //{ TODO: fix or remove this commands
            { "weapon",         SEC_ADMINISTRATOR,  false, &HandleNpcAddWeaponCommand,         "", NULL },
            //}
            { "",               SEC_GAMEMASTER,     false, &HandleNpcAddCommand,               "", NULL },
            { NULL,             0,                  false, NULL,                               "", NULL }
        };
        static ChatCommand npcDeleteCommandTable[] =
        {
            { "item",           SEC_GAMEMASTER,     false, &HandleNpcDeleteVendorItemCommand,  "", NULL },
            { "",               SEC_GAMEMASTER,     false, &HandleNpcDeleteCommand,            "", NULL },
            { NULL,             0,                  false, NULL,                               "", NULL }
        };
        static ChatCommand npcFollowCommandTable[] =
        {
            { "stop",           SEC_GAMEMASTER,     false, &HandleNpcUnFollowCommand,          "", NULL },
            { "",               SEC_GAMEMASTER,     false, &HandleNpcFollowCommand,            "", NULL },
            { NULL,             0,                  false, NULL,                               "", NULL }
        };
        static ChatCommand npcSetCommandTable[] =
        {
            { "allowmove",      SEC_ADMINISTRATOR,  false, &HandleNpcSetAllowMovementCommand,  "", NULL },
            { "deathstate",     SEC_GAMEMASTER,     false, &HandleNpcSetDeathStateCommand,     "", NULL },
            { "entry",          SEC_ADMINISTRATOR,  false, &HandleNpcSetEntryCommand,          "", NULL },
            { "factionid",      SEC_GAMEMASTER,     false, &HandleNpcSetFactionIdCommand,      "", NULL },
            { "flag",           SEC_GAMEMASTER,     false, &HandleNpcSetFlagCommand,           "", NULL },
            { "level",          SEC_GAMEMASTER,     false, &HandleNpcSetLevelCommand,          "", NULL },
            { "link",           SEC_GAMEMASTER,     false, &HandleNpcSetLinkCommand,           "", NULL },
            { "model",          SEC_GAMEMASTER,     false, &HandleNpcSetModelCommand,          "", NULL },
            { "movetype",       SEC_GAMEMASTER,     false, &HandleNpcSetMoveTypeCommand,       "", NULL },
            { "phase",          SEC_GAMEMASTER,     false, &HandleNpcSetPhaseCommand,          "", NULL },
            { "spawndist",      SEC_GAMEMASTER,     false, &HandleNpcSetSpawnDistCommand,      "", NULL },
            { "spawntime",      SEC_GAMEMASTER,     false, &HandleNpcSetSpawnTimeCommand,      "", NULL },
            //{ TODO: fix or remove this commands
            { "name",           SEC_GAMEMASTER,     false, &HandleNpcSetNameCommand,           "", NULL },
            { "subname",        SEC_GAMEMASTER,     false, &HandleNpcSetSubNameCommand,        "", NULL },
            //}
            { NULL,             0,                  false, NULL,                               "", NULL }
        };
        static ChatCommand npcCommandTable[] =
        {
            { "info",           SEC_ADMINISTRATOR,  false, &HandleNpcInfoCommand,              "", NULL },
            { "move",           SEC_GAMEMASTER,     false, &HandleNpcMoveCommand,              "", NULL },
            { "playemote",      SEC_ADMINISTRATOR,  false, &HandleNpcPlayEmoteCommand,         "", NULL },
            { "say",            SEC_MODERATOR,      false, &HandleNpcSayCommand,               "", NULL },
            { "textemote",      SEC_MODERATOR,      false, &HandleNpcTextEmoteCommand,         "", NULL },
            { "whisper",        SEC_MODERATOR,      false, &HandleNpcWhisperCommand,           "", NULL },
            { "yell",           SEC_MODERATOR,      false, &HandleNpcYellCommand,              "", NULL },
            { "tame",           SEC_GAMEMASTER,     false, &HandleNpcTameCommand,              "", NULL },
            { "add",            SEC_GAMEMASTER,     false, NULL,                 "", npcAddCommandTable },
            { "delete",         SEC_GAMEMASTER,     false, NULL,              "", npcDeleteCommandTable },
            { "follow",         SEC_GAMEMASTER,     false, NULL,              "", npcFollowCommandTable },
            { "set",            SEC_GAMEMASTER,     false, NULL,                 "", npcSetCommandTable },
            { NULL,             0,                  false, NULL,                               "", NULL }
        };
        static ChatCommand commandTable[] =
        {
            { "npc",            SEC_MODERATOR,      false, NULL,                    "", npcCommandTable },
            { NULL,             0,                  false, NULL,                               "", NULL }
        };
        return commandTable;
    }

    //add spawn of creature
    static bool HandleNpcAddCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;
        char* charID = handler->extractKeyFromLink((char*)args,"Hcreature_entry");
        if (!charID)
            return false;

        char* team = strtok(NULL, " ");
        int32 teamval = 0;
        if (team) { teamval = atoi(team); }
        if (teamval < 0) { teamval = 0; }

        uint32 id  = atoi(charID);

        Player *chr = handler->GetSession()->GetPlayer();
        float x = chr->GetPositionX();
        float y = chr->GetPositionY();
        float z = chr->GetPositionZ();
        float o = chr->GetOrientation();
        Map *map = chr->GetMap();

        if (chr->GetTransport())
        {
            uint32 tguid = chr->GetTransport()->AddNPCPassenger(0, id, chr->GetTransOffsetX(), chr->GetTransOffsetY(), chr->GetTransOffsetZ(), chr->GetTransOffsetO());
            if (tguid > 0)
                WorldDatabase.PQuery("INSERT INTO creature_transport (guid, npc_entry, transport_entry,  TransOffsetX, TransOffsetY, TransOffsetZ, TransOffsetO) values (%u, %u, %f, %f, %f, %f, %u)", tguid, id, chr->GetTransport()->GetEntry(), chr->GetTransOffsetX(), chr->GetTransOffsetY(), chr->GetTransOffsetZ(), chr->GetTransOffsetO());

            return true;
        }

        Creature* pCreature = new Creature;
        if (!pCreature->Create(sObjectMgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, (uint32)teamval, x, y, z, o))
        {
            delete pCreature;
            return false;
        }

        pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());

        uint32 db_guid = pCreature->GetDBTableGUIDLow();

        // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
        pCreature->LoadFromDB(db_guid, map);

        map->Add(pCreature);
        sObjectMgr.AddCreatureToGrid(db_guid, sObjectMgr.GetCreatureData(db_guid));
        return true;
    }

    //add item in vendorlist
    static bool HandleNpcAddVendorItemCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        char* pitem  = handler->extractKeyFromLink((char*)args,"Hitem");
        if (!pitem)
        {
            handler->SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
            handler->SetSentErrorMessage(true);
            return false;
        }

        uint32 itemId = atol(pitem);

        char* fmaxcount = strtok(NULL, " ");                    //add maxcount, default: 0
        uint32 maxcount = 0;
        if (fmaxcount)
            maxcount = atol(fmaxcount);

        char* fincrtime = strtok(NULL, " ");                    //add incrtime, default: 0
        uint32 incrtime = 0;
        if (fincrtime)
            incrtime = atol(fincrtime);

        char* fextendedcost = strtok(NULL, " ");                //add ExtendedCost, default: 0
        uint32 extendedcost = fextendedcost ? atol(fextendedcost) : 0;
        Creature* vendor = handler->getSelectedCreature();

        if (!vendor)
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        uint32 vendor_entry = vendor ? vendor->GetEntry() : 0;

        if (!sObjectMgr.IsVendorItemValid(vendor_entry,itemId,maxcount,incrtime,extendedcost,handler->GetSession()->GetPlayer()))
        {
            handler->SetSentErrorMessage(true);
            return false;
        }

        sObjectMgr.AddVendorItem(vendor_entry,itemId,maxcount,incrtime,extendedcost);

        ItemPrototype const* pProto = sObjectMgr.GetItemPrototype(itemId);

        handler->PSendSysMessage(LANG_ITEM_ADDED_TO_LIST,itemId,pProto->Name1,maxcount,incrtime,extendedcost);
        return true;
    }

    //add move for creature
    static bool HandleNpcAddMoveCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        char* guid_str = strtok((char*)args, " ");
        char* wait_str = strtok((char*)NULL, " ");

        uint32 lowguid = atoi((char*)guid_str);

        Creature* pCreature = NULL;

        /* FIXME: impossible without entry
        if (lowguid)
        pCreature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT));
        */

        // attempt check creature existence by DB data
        if (!pCreature)
        {
            CreatureData const* data = sObjectMgr.GetCreatureData(lowguid);
            if (!data)
            {
                handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
                handler->SetSentErrorMessage(true);
                return false;
            }
        }
        else
        {
            // obtain real GUID for DB operations
            lowguid = pCreature->GetDBTableGUIDLow();
        }

        int wait = wait_str ? atoi(wait_str) : 0;

        if (wait < 0)
            wait = 0;

        //Player* player = handler->GetSession()->GetPlayer();

        //WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), wait, 0);

        // update movement type
        WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid);
        if (pCreature && pCreature->GetWaypointPath())
        {
            pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
            pCreature->GetMotionMaster()->Initialize();
            if (pCreature->isAlive())                            // dead creature will reset movement generator at respawn
            {
                pCreature->setDeathState(JUST_DIED);
                pCreature->Respawn(true);
            }
            pCreature->SaveToDB();
        }

        handler->SendSysMessage(LANG_WAYPOINT_ADDED);

        return true;
    }

    static bool HandleNpcSetAllowMovementCommand(ChatHandler* handler, const char* /*args*/)
    {
        if (sWorld.getAllowMovement())
        {
            sWorld.SetAllowMovement(false);
            handler->SendSysMessage(LANG_CREATURE_MOVE_DISABLED);
        }
        else
        {
            sWorld.SetAllowMovement(true);
            handler->SendSysMessage(LANG_CREATURE_MOVE_ENABLED);
        }
        return true;
    }

    static bool HandleNpcSetEntryCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        uint32 newEntryNum = atoi(args);
        if (!newEntryNum)
            return false;

        Unit* unit = handler->getSelectedUnit();
        if (!unit || unit->GetTypeId() != TYPEID_UNIT)
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }
        Creature* creature = unit->ToCreature();
        if (creature->UpdateEntry(newEntryNum))
            handler->SendSysMessage(LANG_DONE);
        else
            handler->SendSysMessage(LANG_ERROR);
        return true;
    }

    //change level of creature or pet
    static bool HandleNpcSetLevelCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        uint8 lvl = (uint8) atoi((char*)args);
        if (lvl < 1 || lvl > sWorld.getIntConfig(CONFIG_MAX_PLAYER_LEVEL) + 3)
        {
            handler->SendSysMessage(LANG_BAD_VALUE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        Creature* pCreature = handler->getSelectedCreature();
        if (!pCreature)
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        if (pCreature->isPet())
        {
            if (((Pet*)pCreature)->getPetType() == HUNTER_PET)
            {
                pCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr.GetXPForLevel(lvl)/4);
                pCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
            }
            ((Pet*)pCreature)->GivePetLevel(lvl);
        }
        else
        {
            pCreature->SetMaxHealth(100 + 30*lvl);
            pCreature->SetHealth(100 + 30*lvl);
            pCreature->SetLevel(lvl);
            pCreature->SaveToDB();
        }

        return true;
    }

    static bool HandleNpcDeleteCommand(ChatHandler* handler, const char* args)
    {
        Creature* unit = NULL;

        if (*args)
        {
            // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
            char* cId = handler->extractKeyFromLink((char*)args,"Hcreature");
            if (!cId)
                return false;

            uint32 lowguid = atoi(cId);
            if (!lowguid)
                return false;

            if (CreatureData const* cr_data = sObjectMgr.GetCreatureData(lowguid))
                unit = handler->GetSession()->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(lowguid, cr_data->id, HIGHGUID_UNIT));
        }
        else
            unit = handler->getSelectedCreature();

        if (!unit || unit->isPet() || unit->isTotem())
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        // Delete the creature
        unit->CombatStop();
        unit->DeleteFromDB();
        unit->AddObjectToRemoveList();

        handler->SendSysMessage(LANG_COMMAND_DELCREATMESSAGE);

        return true;
    }

    //del item from vendor list
    static bool HandleNpcDeleteVendorItemCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        Creature* vendor = handler->getSelectedCreature();
        if (!vendor || !vendor->isVendor())
        {
            handler->SendSysMessage(LANG_COMMAND_VENDORSELECTION);
            handler->SetSentErrorMessage(true);
            return false;
        }

        char* pitem  = handler->extractKeyFromLink((char*)args,"Hitem");
        if (!pitem)
        {
            handler->SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
            handler->SetSentErrorMessage(true);
            return false;
        }
        uint32 itemId = atol(pitem);

        if (!sObjectMgr.RemoveVendorItem(vendor->GetEntry(),itemId))
        {
            handler->PSendSysMessage(LANG_ITEM_NOT_IN_LIST,itemId);
            handler->SetSentErrorMessage(true);
            return false;
        }

        ItemPrototype const* pProto = sObjectMgr.GetItemPrototype(itemId);

        handler->PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST,itemId,pProto->Name1);
        return true;
    }

    //set faction of creature
    static bool HandleNpcSetFactionIdCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        uint32 factionId = (uint32) atoi((char*)args);

        if (!sFactionTemplateStore.LookupEntry(factionId))
        {
            handler->PSendSysMessage(LANG_WRONG_FACTION, factionId);
            handler->SetSentErrorMessage(true);
            return false;
        }

        Creature* pCreature = handler->getSelectedCreature();

        if (!pCreature)
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        pCreature->setFaction(factionId);

        // faction is set in creature_template - not inside creature

        // update in memory
        if (CreatureInfo const *cinfo = pCreature->GetCreatureInfo())
        {
            const_cast<CreatureInfo*>(cinfo)->faction_A = factionId;
            const_cast<CreatureInfo*>(cinfo)->faction_H = factionId;
        }

        // and DB
        WorldDatabase.PExecute("UPDATE creature_template SET faction_A = '%u', faction_H = '%u' WHERE entry = '%u'", factionId, factionId, pCreature->GetEntry());

        return true;
    }

    //set npcflag of creature
    static bool HandleNpcSetFlagCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        uint32 npcFlags = (uint32) atoi((char*)args);

        Creature* pCreature = handler->getSelectedCreature();

        if (!pCreature)
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags);

        WorldDatabase.PExecute("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry());

        handler->SendSysMessage(LANG_VALUE_SAVED_REJOIN);

        return true;
    }

    //npc follow handling
    static bool HandleNpcFollowCommand(ChatHandler* handler, const char* /*args*/)
    {
        Player *player = handler->GetSession()->GetPlayer();
        Creature *creature = handler->getSelectedCreature();

        if (!creature)
        {
            handler->PSendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        // Follow player - Using pet's default dist and angle
        creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, creature->GetFollowAngle());

        handler->PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName());
        return true;
    }

    static bool HandleNpcInfoCommand(ChatHandler* handler, const char* /*args*/)
    {
        Creature* target = handler->getSelectedCreature();

        if (!target)
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        uint32 faction = target->getFaction();
        uint32 npcflags = target->GetUInt32Value(UNIT_NPC_FLAGS);
        uint32 displayid = target->GetDisplayId();
        uint32 nativeid = target->GetNativeDisplayId();
        uint32 Entry = target->GetEntry();
        CreatureInfo const* cInfo = target->GetCreatureInfo();

        int64 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL);
        if (curRespawnDelay < 0)
            curRespawnDelay = 0;
        std::string curRespawnDelayStr = secsToTimeString(uint64(curRespawnDelay),true);
        std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true);

        handler->PSendSysMessage(LANG_NPCINFO_CHAR,  target->GetDBTableGUIDLow(), faction, npcflags, Entry, displayid, nativeid);
        handler->PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel());
        handler->PSendSysMessage(LANG_NPCINFO_HEALTH,target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth());
        handler->PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction());
        handler->PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str());
        handler->PSendSysMessage(LANG_NPCINFO_LOOT,  cInfo->lootid,cInfo->pickpocketLootId,cInfo->SkinLootId);
        handler->PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId());
        handler->PSendSysMessage(LANG_NPCINFO_PHASEMASK, target->GetPhaseMask());
        handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor());
        handler->PSendSysMessage(LANG_NPCINFO_POSITION,float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ()));
        if (const CreatureData* const linked = target->GetLinkedRespawnCreatureData())
            if (CreatureInfo const *master = GetCreatureInfo(linked->id))
                handler->PSendSysMessage(LANG_NPCINFO_LINKGUID, sObjectMgr.GetLinkedRespawnGuid(target->GetDBTableGUIDLow()), linked->id, master->Name);

        if ((npcflags & UNIT_NPC_FLAG_VENDOR))
        {
            handler->SendSysMessage(LANG_NPCINFO_VENDOR);
        }
        if ((npcflags & UNIT_NPC_FLAG_TRAINER))
        {
            handler->SendSysMessage(LANG_NPCINFO_TRAINER);
        }

        return true;
    }

    //move selected creature
    static bool HandleNpcMoveCommand(ChatHandler* handler, const char* args)
    {
        uint32 lowguid = 0;

        Creature* pCreature = handler->getSelectedCreature();

        if (!pCreature)
        {
            // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
            char* cId = handler->extractKeyFromLink((char*)args,"Hcreature");
            if (!cId)
                return false;

            lowguid = atoi(cId);

            /* FIXME: impossibel without entry
            if (lowguid)
            pCreature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT));
            */

            // Attempting creature load from DB data
            if (!pCreature)
            {
                CreatureData const* data = sObjectMgr.GetCreatureData(lowguid);
                if (!data)
                {
                    handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
                    handler->SetSentErrorMessage(true);
                    return false;
                }

                uint32 map_id = data->mapid;

                if (handler->GetSession()->GetPlayer()->GetMapId() != map_id)
                {
                    handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
                    handler->SetSentErrorMessage(true);
                    return false;
                }
            }
            else
            {
                lowguid = pCreature->GetDBTableGUIDLow();
            }
        }
        else
        {
            lowguid = pCreature->GetDBTableGUIDLow();
        }

        float x = handler->GetSession()->GetPlayer()->GetPositionX();
        float y = handler->GetSession()->GetPlayer()->GetPositionY();
        float z = handler->GetSession()->GetPlayer()->GetPositionZ();
        float o = handler->GetSession()->GetPlayer()->GetOrientation();

        if (pCreature)
        {
            if (CreatureData const* data = sObjectMgr.GetCreatureData(pCreature->GetDBTableGUIDLow()))
            {
                const_cast<CreatureData*>(data)->posX = x;
                const_cast<CreatureData*>(data)->posY = y;
                const_cast<CreatureData*>(data)->posZ = z;
                const_cast<CreatureData*>(data)->orientation = o;
            }
            pCreature->GetMap()->CreatureRelocation(pCreature,x, y, z,o);
            pCreature->GetMotionMaster()->Initialize();
            if (pCreature->isAlive())                            // dead creature will reset movement generator at respawn
            {
                pCreature->setDeathState(JUST_DIED);
                pCreature->Respawn();
            }
        }

        WorldDatabase.PExecute("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid);
        handler->PSendSysMessage(LANG_COMMAND_CREATUREMOVED);
        return true;
    }

    //play npc emote
    static bool HandleNpcPlayEmoteCommand(ChatHandler* handler, const char* args)
    {
        uint32 emote = atoi((char*)args);

        Creature* target = handler->getSelectedCreature();
        if (!target)
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        if (target->GetTransport())
            if (target->GetGUIDTransport())
                WorldDatabase.PQuery("UPDATE creature_transport SET emote=%u WHERE transport_entry=%u AND guid=%u", emote, target->GetTransport()->GetEntry(), target->GetGUIDTransport());

        target->SetUInt32Value(UNIT_NPC_EMOTESTATE,emote);

        return true;
    }

    //set model of creature
    static bool HandleNpcSetModelCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        uint32 displayId = (uint32) atoi((char*)args);

        Creature *pCreature = handler->getSelectedCreature();

        if (!pCreature || pCreature->isPet())
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        pCreature->SetDisplayId(displayId);
        pCreature->SetNativeDisplayId(displayId);

        pCreature->SaveToDB();

        return true;
    }

    /**HandleNpcSetMoveTypeCommand
    * Set the movement type for an NPC.<br/>
    * <br/>
    * Valid movement types are:
    * <ul>
    * <li> stay - NPC wont move </li>
    * <li> random - NPC will move randomly according to the spawndist </li>
    * <li> way - NPC will move with given waypoints set </li>
    * </ul>
    * additional parameter: NODEL - so no waypoints are deleted, if you
    *                       change the movement type
    */
    static bool HandleNpcSetMoveTypeCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        // 3 arguments:
        // GUID (optional - you can also select the creature)
        // stay|random|way (determines the kind of movement)
        // NODEL (optional - tells the system NOT to delete any waypoints)
        //        this is very handy if you want to do waypoints, that are
        //        later switched on/off according to special events (like escort
        //        quests, etc)
        char* guid_str = strtok((char*)args, " ");
        char* type_str = strtok((char*)NULL, " ");
        char* dontdel_str = strtok((char*)NULL, " ");

        bool doNotDelete = false;

        if (!guid_str)
            return false;

        uint32 lowguid = 0;
        Creature* pCreature = NULL;

        if (dontdel_str)
        {
            //sLog.outError("DEBUG: All 3 params are set");

            // All 3 params are set
            // GUID
            // type
            // doNotDEL
            if (stricmp(dontdel_str, "NODEL") == 0)
            {
                //sLog.outError("DEBUG: doNotDelete = true;");
                doNotDelete = true;
            }
        }
        else
        {
            // Only 2 params - but maybe NODEL is set
            if (type_str)
            {
                sLog.outError("DEBUG: Only 2 params ");
                if (stricmp(type_str, "NODEL") == 0)
                {
                    //sLog.outError("DEBUG: type_str, NODEL ");
                    doNotDelete = true;
                    type_str = NULL;
                }
            }
        }

        if (!type_str)                                           // case .setmovetype $move_type (with selected creature)
        {
            type_str = guid_str;
            pCreature = handler->getSelectedCreature();
            if (!pCreature || pCreature->isPet())
                return false;
            lowguid = pCreature->GetDBTableGUIDLow();
        }
        else                                                    // case .setmovetype #creature_guid $move_type (with selected creature)
        {
            lowguid = atoi((char*)guid_str);

            /* impossible without entry
            if (lowguid)
            pCreature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT));
            */

            // attempt check creature existence by DB data
            if (!pCreature)
            {
                CreatureData const* data = sObjectMgr.GetCreatureData(lowguid);
                if (!data)
                {
                    handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
                    handler->SetSentErrorMessage(true);
                    return false;
                }
            }
            else
            {
                lowguid = pCreature->GetDBTableGUIDLow();
            }
        }

        // now lowguid is low guid really existed creature
        // and pCreature point (maybe) to this creature or NULL

        MovementGeneratorType move_type;

        std::string type = type_str;

        if (type == "stay")
            move_type = IDLE_MOTION_TYPE;
        else if (type == "random")
            move_type = RANDOM_MOTION_TYPE;
        else if (type == "way")
            move_type = WAYPOINT_MOTION_TYPE;
        else
            return false;

        // update movement type
        //if (doNotDelete == false)
        //    WaypointMgr.DeletePath(lowguid);

        if (pCreature)
        {
            // update movement type
            if (doNotDelete == false)
                pCreature->LoadPath(0);

            pCreature->SetDefaultMovementType(move_type);
            pCreature->GetMotionMaster()->Initialize();
            if (pCreature->isAlive())                            // dead creature will reset movement generator at respawn
            {
                pCreature->setDeathState(JUST_DIED);
                pCreature->Respawn();
            }
            pCreature->SaveToDB();
        }
        if (doNotDelete == false)
        {
            handler->PSendSysMessage(LANG_MOVE_TYPE_SET,type_str);
        }
        else
        {
            handler->PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL,type_str);
        }

        return true;
    }

    //npc phasemask handling
    //change phasemask of creature or pet
    static bool HandleNpcSetPhaseCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        uint32 phasemask = (uint32) atoi((char*)args);
        if (phasemask == 0)
        {
            handler->SendSysMessage(LANG_BAD_VALUE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        Creature* pCreature = handler->getSelectedCreature();
        if (!pCreature)
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        pCreature->SetPhaseMask(phasemask,true);

        if (!pCreature->isPet())
            pCreature->SaveToDB();

        return true;
    }

    //set spawn dist of creature
    static bool HandleNpcSetSpawnDistCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        float option = (float)(atof((char*)args));
        if (option < 0.0f)
        {
            handler->SendSysMessage(LANG_BAD_VALUE);
            return false;
        }

        MovementGeneratorType mtype = IDLE_MOTION_TYPE;
        if (option >0.0f)
            mtype = RANDOM_MOTION_TYPE;

        Creature *pCreature = handler->getSelectedCreature();
        uint32 u_guidlow = 0;

        if (pCreature)
            u_guidlow = pCreature->GetDBTableGUIDLow();
        else
            return false;

        pCreature->SetRespawnRadius((float)option);
        pCreature->SetDefaultMovementType(mtype);
        pCreature->GetMotionMaster()->Initialize();
        if (pCreature->isAlive())                                // dead creature will reset movement generator at respawn
        {
            pCreature->setDeathState(JUST_DIED);
            pCreature->Respawn();
        }

        WorldDatabase.PExecute("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow);
        handler->PSendSysMessage(LANG_COMMAND_SPAWNDIST,option);
        return true;
    }

    //spawn time handling
    static bool HandleNpcSetSpawnTimeCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        char* stime = strtok((char*)args, " ");

        if (!stime)
            return false;

        int i_stime = atoi((char*)stime);

        if (i_stime < 0)
        {
            handler->SendSysMessage(LANG_BAD_VALUE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        Creature *pCreature = handler->getSelectedCreature();
        uint32 u_guidlow = 0;

        if (pCreature)
            u_guidlow = pCreature->GetDBTableGUIDLow();
        else
            return false;

        WorldDatabase.PExecute("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow);
        pCreature->SetRespawnDelay((uint32)i_stime);
        handler->PSendSysMessage(LANG_COMMAND_SPAWNTIME,i_stime);

        return true;
    }

    static bool HandleNpcSayCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        Creature* pCreature = handler->getSelectedCreature();
        if (!pCreature)
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        pCreature->MonsterSay(args, LANG_UNIVERSAL, 0);

        // make some emotes
        char lastchar = args[strlen(args) - 1];
        switch(lastchar)
        {
        case '?':   pCreature->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION);      break;
        case '!':   pCreature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION);   break;
        default:    pCreature->HandleEmoteCommand(EMOTE_ONESHOT_TALK);          break;
        }

        return true;
    }

    //show text emote by creature in chat
    static bool HandleNpcTextEmoteCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        Creature* pCreature = handler->getSelectedCreature();

        if (!pCreature)
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        pCreature->MonsterTextEmote(args, 0);

        return true;
    }

    //npc unfollow handling
    static bool HandleNpcUnFollowCommand(ChatHandler* handler, const char* /*args*/)
    {
        Player *player = handler->GetSession()->GetPlayer();
        Creature *creature = handler->getSelectedCreature();

        if (!creature)
        {
            handler->PSendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        if (/*creature->GetMotionMaster()->empty() ||*/
            creature->GetMotionMaster()->GetCurrentMovementGeneratorType () != TARGETED_MOTION_TYPE)
        {
            handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName());
            handler->SetSentErrorMessage(true);
            return false;
        }

        TargetedMovementGenerator<Creature> const* mgen
            = static_cast<TargetedMovementGenerator<Creature> const*>((creature->GetMotionMaster()->top()));

        if (mgen->GetTarget() != player)
        {
            handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName());
            handler->SetSentErrorMessage(true);
            return false;
        }

        // reset movement
        creature->GetMotionMaster()->MovementExpired(true);

        handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName());
        return true;
    }

    // make npc whisper to player
    static bool HandleNpcWhisperCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        char* receiver_str = strtok((char*)args, " ");
        char* text = strtok(NULL, "");

        uint64 guid = handler->GetSession()->GetPlayer()->GetSelection();
        Creature* pCreature = handler->GetSession()->GetPlayer()->GetMap()->GetCreature(guid);

        if (!pCreature || !receiver_str || !text)
        {
            return false;
        }

        uint64 receiver_guid= atol(receiver_str);

        // check online security
        if (handler->HasLowerSecurity(sObjectMgr.GetPlayer(receiver_guid), 0))
            return false;

        pCreature->MonsterWhisper(text,receiver_guid);

        return true;
    }

    static bool HandleNpcYellCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        Creature* pCreature = handler->getSelectedCreature();
        if (!pCreature)
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        pCreature->MonsterYell(args, LANG_UNIVERSAL, 0);

        // make an emote
        pCreature->HandleEmoteCommand(EMOTE_ONESHOT_SHOUT);

        return true;
    }

    // add creature, temp only
    static bool HandleNpcAddTempSpawnCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;
        char* charID = strtok((char*)args, " ");
        if (!charID)
            return false;

        Player *chr = handler->GetSession()->GetPlayer();

        uint32 id = atoi(charID);
        if (!id)
            return false;

        chr->SummonCreature(id, *chr, TEMPSUMMON_CORPSE_DESPAWN, 120);

        return true;
    }

    //npc tame handling
    static bool HandleNpcTameCommand(ChatHandler* handler, const char* /*args*/)
    {
        Creature *creatureTarget = handler->getSelectedCreature ();
        if (!creatureTarget || creatureTarget->isPet ())
        {
            handler->PSendSysMessage (LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage (true);
            return false;
        }

        Player *player = handler->GetSession()->GetPlayer ();

        if (player->GetPetGUID ())
        {
            handler->SendSysMessage (LANG_YOU_ALREADY_HAVE_PET);
            handler->SetSentErrorMessage (true);
            return false;
        }

        CreatureInfo const* cInfo = creatureTarget->GetCreatureInfo();

        if (!cInfo->isTameable (player->CanTameExoticPets()))
        {
            handler->PSendSysMessage (LANG_CREATURE_NON_TAMEABLE,cInfo->Entry);
            handler->SetSentErrorMessage (true);
            return false;
        }

        // Everything looks OK, create new pet
        Pet* pet = player->CreateTamedPetFrom (creatureTarget);
        if (!pet)
        {
            handler->PSendSysMessage (LANG_CREATURE_NON_TAMEABLE,cInfo->Entry);
            handler->SetSentErrorMessage (true);
            return false;
        }

        // place pet before player
        float x,y,z;
        player->GetClosePoint (x,y,z,creatureTarget->GetObjectSize (),CONTACT_DISTANCE);
        pet->Relocate (x,y,z,M_PI-player->GetOrientation ());

        // set pet to defensive mode by default (some classes can't control controlled pets in fact).
        pet->SetReactState(REACT_DEFENSIVE);

        // calculate proper level
        uint8 level = (creatureTarget->getLevel() < (player->getLevel() - 5)) ? (player->getLevel() - 5) : creatureTarget->getLevel();

        // prepare visual effect for levelup
        pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);

        // add to world
        pet->GetMap()->Add(pet->ToCreature());

        // visual effect for levelup
        pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);

        // caster have pet now
        player->SetMinion(pet, true);

        pet->SavePetToDB(PET_SAVE_AS_CURRENT);
        player->PetSpellInitialize();

        return true;
    }

    //npc deathstate handling
    static bool HandleNpcSetDeathStateCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        Creature* pCreature = handler->getSelectedCreature();
        if (!pCreature || pCreature->isPet())
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        if (strncmp(args, "on", 3) == 0)
            pCreature->SetDeadByDefault(true);
        else if (strncmp(args, "off", 4) == 0)
            pCreature->SetDeadByDefault(false);
        else
        {
            handler->SendSysMessage(LANG_USE_BOL);
            handler->SetSentErrorMessage(true);
            return false;
        }

        pCreature->SaveToDB();
        pCreature->Respawn();

        return true;
    }

    static bool HandleNpcAddFormationCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        uint32 leaderGUID = (uint32) atoi((char*)args);
        Creature *pCreature = handler->getSelectedCreature();

        if (!pCreature || !pCreature->GetDBTableGUIDLow())
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        uint32 lowguid = pCreature->GetDBTableGUIDLow();
        if (pCreature->GetFormation())
        {
            handler->PSendSysMessage("Selected creature is already member of group %u", pCreature->GetFormation()->GetId());
            return false;
        }

        if (!lowguid)
            return false;

        Player *chr = handler->GetSession()->GetPlayer();
        FormationInfo *group_member;

        group_member                 = new FormationInfo;
        group_member->follow_angle   = (pCreature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI;
        group_member->follow_dist    = sqrtf(pow(chr->GetPositionX() - pCreature->GetPositionX(),int(2))+pow(chr->GetPositionY()-pCreature->GetPositionY(),int(2)));
        group_member->leaderGUID     = leaderGUID;
        group_member->groupAI        = 0;

        CreatureGroupMap[lowguid] = group_member;
        pCreature->SearchFormation();

        WorldDatabase.PExecute("INSERT INTO creature_formations (leaderGUID, memberGUID, dist, angle, groupAI) VALUES ('%u','%u','%f', '%f', '%u')",
            leaderGUID, lowguid, group_member->follow_dist, group_member->follow_angle, group_member->groupAI);

        handler->PSendSysMessage("Creature %u added to formation with leader %u", lowguid, leaderGUID);

        return true;
    }

    static bool HandleNpcSetLinkCommand(ChatHandler* handler, const char* args)
    {
        if (!*args)
            return false;

        uint32 linkguid = (uint32) atoi((char*)args);

        Creature* pCreature = handler->getSelectedCreature();

        if (!pCreature)
        {
            handler->SendSysMessage(LANG_SELECT_CREATURE);
            handler->SetSentErrorMessage(true);
            return false;
        }

        if (!pCreature->GetDBTableGUIDLow())
        {
            handler->PSendSysMessage("Selected creature %u isn't in creature table", pCreature->GetGUIDLow());
            handler->SetSentErrorMessage(true);
            return false;
        }

        if (!sObjectMgr.SetCreatureLinkedRespawn(pCreature->GetDBTableGUIDLow(), linkguid))
        {
            handler->PSendSysMessage("Selected creature can't link with guid '%u'", linkguid);
            handler->SetSentErrorMessage(true);
            return false;
        }

        handler->PSendSysMessage("LinkGUID '%u' added to creature with DBTableGUID: '%u'", linkguid, pCreature->GetDBTableGUIDLow());
        return true;
    }

    //TODO: NpcCommands that needs to be fixed :
    static bool HandleNpcAddWeaponCommand(ChatHandler* handler, const char* /*args*/)
    {
        /*if (!*args)
        return false;

        uint64 guid = handler->GetSession()->GetPlayer()->GetSelection();
        if (guid == 0)
        {
        handler->SendSysMessage(LANG_NO_SELECTION);
        return true;
        }

        Creature *pCreature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), guid);

        if (!pCreature)
        {
        handler->SendSysMessage(LANG_SELECT_CREATURE);
        return true;
        }

        char* pSlotID = strtok((char*)args, " ");
        if (!pSlotID)
        return false;

        char* pItemID = strtok(NULL, " ");
        if (!pItemID)
        return false;

        uint32 ItemID = atoi(pItemID);
        uint32 SlotID = atoi(pSlotID);

        ItemPrototype* tmpItem = sObjectMgr.GetItemPrototype(ItemID);

        bool added = false;
        if (tmpItem)
        {
        switch(SlotID)
        {
        case 1:
        pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID);
        added = true;
        break;
        case 2:
        pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID);
        added = true;
        break;
        case 3:
        pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID);
        added = true;
        break;
        default:
        handler->PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST,SlotID);
        added = false;
        break;
        }

        if (added)
        handler->PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT,ItemID,tmpItem->Name1,SlotID);
        }
        else
        {
        handler->PSendSysMessage(LANG_ITEM_NOT_FOUND,ItemID);
        return true;
        }
        */
        return true;
    }

    static bool HandleNpcSetNameCommand(ChatHandler* handler, const char* /*args*/)
    {
        /* Temp. disabled
        if (!*args)
        return false;

        if (strlen((char*)args)>75)
        {
        handler->PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75);
        return true;
        }

        for (uint8 i = 0; i < strlen(args); ++i)
        {
        if (!isalpha(args[i]) && args[i] != ' ')
        {
        handler->SendSysMessage(LANG_CHARS_ONLY);
        return false;
        }
        }

        uint64 guid;
        guid = handler->GetSession()->GetPlayer()->GetSelection();
        if (guid == 0)
        {
        handler->SendSysMessage(LANG_NO_SELECTION);
        return true;
        }

        Creature* pCreature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), guid);

        if (!pCreature)
        {
        handler->SendSysMessage(LANG_SELECT_CREATURE);
        return true;
        }

        pCreature->SetName(args);
        uint32 idname = sObjectMgr.AddCreatureTemplate(pCreature->GetName());
        pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);

        pCreature->SaveToDB();
        */

        return true;
    }

    static bool HandleNpcSetSubNameCommand(ChatHandler* handler, const char* /*args*/)
    {
        /* Temp. disabled

        if (!*args)
        args = "";

        if (strlen((char*)args)>75)
        {
        handler->PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75);
        return true;
        }

        for (uint8 i = 0; i < strlen(args); i++)
        {
        if (!isalpha(args[i]) && args[i] != ' ')
        {
        handler->SendSysMessage(LANG_CHARS_ONLY);
        return false;
        }
        }
        uint64 guid;
        guid = handler->GetSession()->GetPlayer()->GetSelection();
        if (guid == 0)
        {
        handler->SendSysMessage(LANG_NO_SELECTION);
        return true;
        }

        Creature* pCreature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), guid);

        if (!pCreature)
        {
        handler->SendSysMessage(LANG_SELECT_CREATURE);
        return true;
        }

        uint32 idname = sObjectMgr.AddCreatureSubName(pCreature->GetName(),args,pCreature->GetUInt32Value(UNIT_FIELD_DISPLAYID));
        pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);

        pCreature->SaveToDB();
        */
        return true;
    }
    //----------------------------------------------------------
};

void AddSC_npc_commandscript()
{
    new npc_commandscript();
}
